package com.ctsi.organise.service;

import com.ctsi.commons.util.UtilMisc;
import com.ctsi.commons.util.UtilValidate;
import com.ctsi.commons.util.id.UUIDGenerator;
import com.ctsi.commons.util.request.UtilHttp;
import com.ctsi.commons.util.response.Page;
import com.ctsi.framework.elementui.support.TreeNode;
import com.ctsi.framework.mybatis.support.VoTemplate;
import com.ctsi.organise.common.constant.AccountStatus;
import com.ctsi.organise.common.constant.PartyStatus;
import com.ctsi.organise.common.constant.PartyType;
import com.ctsi.organise.common.model.Organise;
import com.ctsi.organise.common.model.Person;
import com.ctsi.organise.common.model.UserLogin;
import com.ctsi.organise.dto.PersonInfoDTO;
import com.ctsi.organise.entity.OrganiseEntity;
import com.ctsi.organise.entity.PartyEntity;
import com.ctsi.organise.entity.PersonEntity;
import com.ctsi.organise.entity.UserLoginEntity;
import com.ctsi.organise.query.OrganiseQuery;
import com.ctsi.organise.query.PersonQuery;
import com.ctsi.organise.vo.*;
import com.ctsi.security.ISecurity;
import com.ctsi.security.domain.DataObject;
import com.ctsi.security.service.DataObjectService;
import com.ctsi.security.service.SRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: zhangjw
 * @Date: 2018/11/15 11:41
 * @Description:
 */
@Service
public class OrganiseServiceImpl implements IOrganiseService  {

    @Autowired
    private OrganiseEntityManager organiseEntityManager;
    @Autowired
    private VoTemplate voTemplate;
    @Autowired
    private ISecurity isecurity;
    @Autowired
    private PartyEntityManager partyEntityManager;
    @Autowired
    private OrganiseStructManager organiseStructManager;
    @Autowired
    private PersonEntityManager personEntityManager;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserLoginEntityManager userLoginEntityManager;

    /**
     * 带权限的返回组织树节点
     *
     * @param userLogin
     * @param partyId
     * @return
     */
    @Override
    public List<TreeNode> getChildTreeNode(String userLogin, String partyId) {
        List<OrganiseEntity> result = null;
        Map<String,Object> params = new HashMap<>();
        params.put("parentId", partyId);
        if (!isecurity.isControl(userLogin, "organChain", "SELECT") || "0".equalsIgnoreCase(partyId)) {
            result = this.organiseEntityManager.find(params);
        } else {
            Set<String> dataObjectIds = isecurity.findDataObjectIds(userLogin, "organChain", "SELECT");
            if (UtilValidate.isNotEmpty(dataObjectIds)) {
                params.put("dataObjectIds", dataObjectIds);
                result = this.organiseEntityManager.find(params);
            }
        }
        if (UtilValidate.isNotEmpty(result)) {
            return result.stream().map(o -> {
                return TreeNode.init(o.getPartyId(), Optional.ofNullable(o.getShortName()).
                        orElse(o.getOrganiseName()), organiseEntityManager.isLeaf(o.getPartyId()), o.getPartyId() == "root");
            }).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }


    /**
     * 带权限的返回组织下的所有子孙组织
     *
     * @param userLogin      用户登陆ID
     * @param dataObjectType 数据对象类型
     * @param action         动作
     * @param partyId        组织ID
     * @return
     */
    @Override
    public List<OrganiseVO> findAllOrganisePrivileged(String userLogin, String dataObjectType, String action, String partyId) {

        return null;
    }

    /**
     * 帶權限返回一组织下的所有人员
     *
     * @param userLogin      用户登陆ID
     * @param dataObjectType 数据对象类型
     * @param action         动作
     * @param partyId        组织ID
     * @return
     */
    @Override
    public List<Person> findAllPersonPrivileged(String userLogin, String dataObjectType, String action, String partyId) {
        return null;
    }

    /**
     * 帶權限返回一组织下的所有登录用户
     *
     * @param userLogin      用户登陆ID
     * @param dataObjectType 数据对象类型
     * @param action         动作
     * @param partyId        组织ID
     * @return
     */
    @Override
    public List<UserLogin> findAllLoginUserPrivileged(String userLogin, String dataObjectType, String action, String partyId) {
        return null;
    }

    /**
     * 一组织是否包含另一组织
     *
     * @param superId 父组织ID
     * @param subId   子组织ID
     * @return
     */
    @Override
    public boolean isContain(String superId, String subId) {
        return false;
    }

    /**
     * 根據类型返回所有的子孙组织
     *
     * @param partyId   组织ID
     * @param partyType 组织类型
     * @return
     */
    @Override
    public List<Organise> findAllOrganise(String partyId, PartyType partyType) {
        return null;
    }

    /**
     * 根据类型返回所有的子孙人员
     *
     * @param partyId   组织ID
     * @param partyType 组织类型
     * @return
     */
    @Override
    public List<Person> findAllPerson(String partyId, PartyType partyType) {
        return null;
    }

    /**
     * 根据类型返回所有的子孙登录用户
     *
     * @param partyId   组织ID
     * @param partyType 组织类型
     * @return
     */
    @Override
    public List<UserLogin> findAllLoginUser(String partyId, PartyType partyType) {
        return null;
    }

    /**
     * 添加组织 ，同时维护闭包表
     *
     * @param organise
     * @param publishEvent
     *
     */
    @Override
    public void addOrganise(AddOrganVO organise,String userId,boolean publishEvent) {
        String partyId = UUIDGenerator.getId();
        OrganiseEntity organ = this.voTemplate.defaultExcute(new OrganiseEntity(), organise);
        organ.setId(partyId);
        PartyEntity party = this.voTemplate.defaultExcute(new PartyEntity(), organise);
        party.setCreateBy(userId);
        party.setCreateTime(System.currentTimeMillis());
        party.setId(partyId);
        party.setOrderNo(organiseEntityManager.findMaxOrderNo()+1);

        organiseEntityManager.insertOrganiseEntity(organ);
        // 递归存储闭包表
        organiseStructManager.organiseJoin(organ);
        if(publishEvent) {
            // TODO: 发布添加组织事件
        }
        String parentId = organise.getParentId();
        OrganiseEntity org = organiseEntityManager.findOrganiseEntityById(parentId);
        String parentDataObjectId = org.getDataObjectId();
//        int pdid = Integer.parseInt(parentDataObjectId);
//        String now = parentDataObjectId + String.valueOf(pdid++);
        String now = UUIDGenerator.getId();
        party.setDataObjectId(now);
        partyEntityManager.insertPartyEntity(party);

        DataObject data = new DataObject();
        data.setId(UUIDGenerator.getId());
        data.setDataObjectId(now);
        data.setDataObjectName(organise.getOrganiseName()+"[数据权限]");
        data.setDescription(organise.getOrganiseName()+"[数据权限]");
        data.setDataObjectTypeId("organChain");
        if (parentId.equalsIgnoreCase("root")) {
            data.setParent("organChain");
        }else{
            data.setParent(parentDataObjectId);
        }
        data.setOrderNo(dataObjectService.getMaxOrderNo()+1);
        data.setDataObjectTypeName("组织结构数据权限");
        data.setSysDataObjectid("sysSecurity");
        dataObjectService.saveDataObject(data);
        //自动创建地市管理员角色
//        if (organise.getPartyTypeId() == PartyType.MINORGAN.value ) {
//            // 组织管理员
//            SRole role = new SRole();
//            role.setOrganiseName(organise.getOrganiseName());
//            role.setOrganiseId(partyId);
//            role.setSortNum(System.currentTimeMillis());
//            role.setRoleId(UUIDGenerator.getId());
//            role.setRoleName(organ.getPartyName()+"[组织结构管理员]");
//            role.setDescription(organ.getPartyName()+"[组织结构管理员]");
//            role.setDataObject(now);
//            role.setRoleType("organManager");
//            sroleService.addRole(role);
//            // 地市数据权限角色
//            // 支撑经理
//            SRole supportor = new SRole();
//            supportor.setOrganiseName(organise.getOrganiseName());
//            supportor.setOrganiseId(partyId);
//            supportor.setSortNum(System.currentTimeMillis());
//            supportor.setRoleId(UUIDGenerator.getId());
//            supportor.setRoleName("["+organ.getPartyName()+"]-支撑流程-支撑经理角色");
//            supportor.setDescription("["+organ.getPartyName()+"]-支撑流程-支撑经理角色");
//            supportor.setDataObject(now);
//            supportor.setRoleType("flow-supportor-role");
//            sroleService.addRole(supportor);
//            //客户经理角色
//            SRole cm = new SRole();
//            cm.setOrganiseName(organise.getOrganiseName());
//            cm.setOrganiseId(partyId);
//            cm.setSortNum(System.currentTimeMillis());
//            cm.setRoleId(UUIDGenerator.getId());
//            cm.setRoleName("["+organ.getPartyName()+"]-支撑流程-客户经理角色");
//            cm.setDescription("["+organ.getPartyName()+"]-支撑流程-客户经理角色");
//            cm.setDataObject(now);
//            cm.setRoleType("flow-coustom-role");
//            sroleService.addRole(cm);
//            // 政支主任角色
//            SRole zhuren = new SRole();
//            zhuren.setOrganiseName(organise.getOrganiseName());
//            zhuren.setOrganiseId(partyId);
//            zhuren.setSortNum(System.currentTimeMillis());
//            zhuren.setRoleId(UUIDGenerator.getId());
//            zhuren.setRoleName("["+organ.getPartyName()+"]-支撑流程-政支主任(接口人)角色");
//            zhuren.setDescription("["+organ.getPartyName()+"]-支撑流程-政支主任(接口人)角色");
//            zhuren.setDataObject(now);
//            zhuren.setRoleType("flow-zhuren-role");
//            sroleService.addRole(zhuren);
//            // 协同部门接口人角色
//            SRole xietong = new SRole();
//            xietong.setOrganiseName(organise.getOrganiseName());
//            xietong.setOrganiseId(partyId);
//            xietong.setSortNum(System.currentTimeMillis());
//            xietong.setRoleId(UUIDGenerator.getId());
//            xietong.setRoleName("["+organ.getPartyName()+"]-支撑流程-协同部门接口人角色");
//            xietong.setDescription("["+organ.getPartyName()+"]-支撑流程-协同部门接口人角色");
//            xietong.setDataObject(now);
//            xietong.setRoleType("flow-xietong-role");
//            sroleService.addRole(xietong);
//            // 协同专家角色
//            SRole asster = new SRole();
//            asster.setOrganiseName(organise.getOrganiseName());
//            asster.setOrganiseId(partyId);
//            asster.setSortNum(System.currentTimeMillis());
//            asster.setRoleId(UUIDGenerator.getId());
//            asster.setRoleName("["+organ.getPartyName()+"]-支撑流程-协同部门专家组角色");
//            asster.setDescription("["+organ.getPartyName()+"]-支撑流程-协同部门专家组角色");
//            asster.setDataObject(now);
//            asster.setRoleType("flow-asster-role");
//            sroleService.addRole(asster);
//            //解决方案中心主任或集成
//            SRole depart = new SRole();
//            depart.setOrganiseName(organise.getOrganiseName());
//            depart.setOrganiseId(partyId);
//            depart.setSortNum(System.currentTimeMillis());
//            depart.setRoleId(UUIDGenerator.getId());
//            depart.setRoleName("["+organ.getPartyName()+"]-支撑流程-解决方案中心或集成接口人角色");
//            depart.setDescription("["+organ.getPartyName()+"]-支撑流程-解决方案中心或集成接口人角色");
//            depart.setDataObject(now);
//            depart.setRoleType("flow-depart-role");
//            sroleService.addRole(depart);
//        }
    }

    @Autowired
    private DataObjectService dataObjectService;
    @Autowired
    private SRoleService sroleService;

    /**
     * 添加人员，同时添加登陆账号
     *
     * @param personVO
     * @param userId 创建人ID
     * @param publishEvent
     */
    @Override
    public String addPersonWithAcc(AddPersonVO personVO, String userId, boolean publishEvent) {
        String uuid = UUIDGenerator.getId();
        PartyEntity party = voTemplate.defaultExcute(new PartyEntity(), personVO);
        party.setId(uuid);
        party.setCreateBy(userId);
        party.setCreateTime(System.currentTimeMillis());
        party.setPartyTypeId(PartyType.PERSON.value);
        PersonEntity person = voTemplate.defaultExcute(new PersonEntity(), personVO);
        person.setPartyId(uuid);
        UserLoginEntity userLogin = voTemplate.defaultExcute(new UserLoginEntity(), personVO);
        userLogin.setCreateBy(userId);
        userLogin.setPartyId(uuid);
        userLogin.setCreateTime(System.currentTimeMillis());
        userLogin.setPassword(passwordEncoder.encode(personVO.getPassword()));
        userLogin.setStatusId(AccountStatus.NORMAL.value);

        //继承组织得数据权限
        String organId = personVO.getOrganId();
        Organise org = organiseEntityManager.findOrganiseEntityById(organId);
        String dataObjectId = org.getDataObjectId();
        party.setDataObjectId(dataObjectId);

        partyEntityManager.insertPartyEntity(party);
        personEntityManager.insertPersonEntity(person);
        personEntityManager.savePersonToOrgan(personVO.getOrganId(), uuid, 1,true);
        userLoginEntityManager.addUserLogin(userLogin,true);

        return uuid;
    }


    /**
     * 组织结构查询分页
     * @param query
     * @param start
     * @param pageSize
     * @return
     */
    @Override
    public Page<OrganiseVO> page(OrganiseQuery query,String loginUserId, int start, int pageSize){
        Map<String,Object> params = UtilHttp.filterBlank(UtilMisc.toMap(query));
        if (!isecurity.isControl(loginUserId, "organChain", "SELECT")) {
            return toOrganVo(this.organiseEntityManager.findByMulitCondition(params, start, pageSize));
        } else {
            Set<String> dataObjectIds = isecurity.findDataObjectIds(loginUserId, "organChain", "SELECT");
            if (UtilValidate.isNotEmpty(dataObjectIds)) {
                params.put("dataObjects", dataObjectIds);
                return toOrganVo(this.organiseEntityManager.findByMulitCondition(params, start, pageSize));
            }
            return new Page<>();
        }
    }

    /**
     *
     * @param query
     * @param loginUserId
     * @param start
     * @param pageSize
     * @return
     */
    @Override
    public Page<PersonVO> personPageQueryPrivileged(PersonQuery query, String loginUserId, int start, int pageSize) {
        Map<String,Object> params = UtilHttp.filterBlank(UtilMisc.toMap(query));
        if (!isecurity.isControl(loginUserId, "organChain", "SELECT")) {
            return toPersonVo(this.personEntityManager.findByMulitCondition(params, start, pageSize));
        } else {
            Set<String> dataObjectIds = isecurity.findDataObjectIds(loginUserId, "organChain", "SELECT");
            if (UtilValidate.isNotEmpty(dataObjectIds)) {
                params.put("dataObjects", dataObjectIds);
                return toPersonVo(this.personEntityManager.findByMulitCondition(params, start, pageSize));
            }
            return new Page<>();
        }
    }

    /**
     * 带权限的逻辑删除
     *
     * @param UserLogin
     * @param partyId
     */
    @Override
    public void logicallyDelete(String UserLogin, String partyId) {
        // TODO：控制权限
        partyEntityManager.logicallyDelete(partyId);
    }

    /**
     * 带权限的编辑
     *
     * @param userlogin
     * @param partyId
     */
    @Override
    public EditOrganVO editPrivileged(String userlogin, String partyId) {
        // TODO: 权限
        OrganiseEntity organ = organiseEntityManager.editOrganiseEntityById(partyId);
        return voTemplate.defaultExcute(new EditOrganVO(), organ);
    }

    /**
     * 带权限的更新
     *
     * @param userLogin
     * @param organVO
     */
    @Override
    public void updatePrivileged(String userLogin,String updateBy, EditOrganVO organVO) {
        OrganiseEntity organ = voTemplate.defaultExcute(new OrganiseEntity(), organVO);
        organ.setUpdateBy(updateBy);
        organ.setLastUpdateTime(System.currentTimeMillis());
        PartyEntity party = voTemplate.defaultExcute(new PartyEntity(), organ);
        partyEntityManager.updatePartyEntityByPKSelective(party);
        organiseEntityManager.updateOrganiseEntityByPKSelective(organ);
    }

    /**
     * 删除用户
     *
     * @param userLogin
     * @param partyIds
     */
    @Override
    public void logicallyDeletePerson(String userLogin, List<String> partyIds) {
        partyIds.stream().forEach(partyId ->{
            PartyEntity party = new PartyEntity();
            party.setId(partyId);
            party.setStatusId(PartyStatus.deleted.value);
            partyEntityManager.updatePartyEntityByPKSelective(party);
        });
    }

    /**
     * 物理删除人员
     *
     * @param userlogin
     * @param partyIds
     */
    @Override
    public void physicDelPerson(String userlogin, List<String> partyIds) {
        // TODO: 完成物理删除
        partyIds.stream().forEach(partyId -> {
            partyEntityManager.removePartyEntity(partyId);
            personEntityManager.removePersonEntity(partyId);
           // userLoginEntityManager.removeUserLoginEntity();
        });
    }

    /**
     * 转换VO
     * @param page
     * @return
     */
    private Page<OrganiseVO> toOrganVo (Page<OrganiseEntity> page){
        List<OrganiseVO> result = page.getResult()
                .stream()
                .map(organiseEntity -> voTemplate.defaultExcute(new OrganiseVO(), organiseEntity)).collect(Collectors.toList());

        Page<OrganiseVO> resultPage = new Page();

        return resultPage.copy(page,result );
    }


    private Page<PersonVO> toPersonVo (Page<PersonInfoDTO> page) {
        List<PersonVO> result = page.getResult()
                .stream()
                .map(personInfoDTO -> {
                   PersonVO vo = voTemplate.defaultExcute(new PersonVO(), personInfoDTO);
                    String userId = personInfoDTO.getPartyId();
                   Organise organise = personEntityManager.getUserDefaultOrgan(userId);
                    vo.setOrganId(organise.getPartyId());
                    List<OrganiseEntity> chains = organiseEntityManager.getOrganiseChain(organise.getPartyId());
                    vo.setOrganChainName(chains.stream().map(chain -> {
                        return UtilValidate.isNotEmpty(chain.getShortName()) ? chain.getShortName() : chain.getOrganiseName();
                    }).collect(Collectors.joining(" > ")));
                   return vo;
                }).collect(Collectors.toList());

        Page<PersonVO> resultPage = new Page();
        return resultPage.copy(page,result );
    }
}
